home *** CD-ROM | disk | FTP | other *** search
- /***
- * sonicpatch.c
- *
- * Make sounds from the debugger over midi
- *
- * by Bernie Bernstein for and entirely during MacHack '93 (June 16-18)
- *
- * thanks to Chris DiGiano for the basis for midi functions
- *
- * thanks to all the MacHackers for help getting this to work
- ***/
-
- #ifndef THINK_C
- #include <Types.h>
- #include <Quickdraw.h>
- #include <Memory.h>
- #include <OSUtils.h>
- #include <Traps.h>
- #include <Files.h>
- #include <Resources.h>
- #include <Packages.h>
- #endif
-
- #ifdef SONICDCMD
- #include "dcmd.h"
- #endif
-
- #ifdef SONICINIT
- #include "utils.h"
- #endif
-
- #include <MIDI.h>
-
- #include "midistuff.h"
-
-
- SonicGlobs gGlobals;
-
- /* fake out the compiler to find the icon */
- /* used by the dcmd and the init */
- void MidiIcon(void);
-
-
-
- #ifdef SONICDCMD
-
- /***
- * CommandEntry
- *
- * the entry point for the dcmd
- ***/
- pascal void CommandEntry (dcmdBlock* paramPtr)
- {
- Str255 param;
-
- switch (paramPtr->request)
- {
- case dcmdInit:
- gGlobals.soundEnabled = false;
- gGlobals.manualPatch = false;
- gGlobals.outputRefNum = 0;
- gGlobals.gotIcon = false;
- LoadIcon();
- break;
-
- case dcmdHelp:
- dcmdDrawLine ("\pPlay [on | connect | off |");
- dcmdDrawLine ("\p { note | stop } [channel [pitch [velocity]]]] |");
- dcmdDrawLine ("\p setchan channel instrument]");
- dcmdDrawLine ("\p Tell midi to play something");
- break;
-
- case dcmdDoIt:
- dcmdGetNextParameter(param);
-
- if (!gGlobals.gotIcon)
- {
- dcmdDrawLine("\pCan't do midi, icon didn't get loaded");
- return;
- }
-
- if (Pstrcmp(param, "\pon") == 0)
- {
- InitMidi();
- }
- else if (Pstrcmp(param, "\pconnect") == 0)
- {
- MIDIManagerConnect();
- }
- else if (Pstrcmp(param, "\poff") == 0)
- {
- KillMidi();
- }
- else if (Pstrcmp(param, "\pnote") == 0)
- {
- long val;
- char channel, pitch, velocity;
- Boolean ok;
-
- channel = 1;
- pitch = 64;
- velocity = 127;
- dcmdGetNextExpression(&val, &ok);
- if (ok)
- {
- channel = val;
- dcmdGetNextExpression(&val, &ok);
- if (ok)
- {
- pitch = val;
- dcmdGetNextExpression(&val, &ok);
- if (ok)
- {
- velocity = val;
- }
- }
- }
- StartNote(channel, pitch, velocity);
- }
- else if (Pstrcmp(param, "\pstop") == 0)
- {
- long val;
- char channel, pitch;
- Boolean ok;
-
- channel = 1;
- pitch = -1;
- dcmdGetNextExpression(&val, &ok);
- channel = val;
- if (ok)
- {
- dcmdGetNextExpression(&val, &ok);
- pitch = val;
- }
- StopNote(channel, pitch);
- }
- else if (Pstrcmp(param, "\psetchan") == 0)
- {
- long val;
- char channel, instrument;
- Boolean ok;
-
- dcmdGetNextExpression(&val, &ok);
- channel = val;
- if (ok)
- {
- dcmdGetNextExpression(&val, &ok);
- instrument = val;
- }
- if (!ok)
- {
- dcmdDrawLine("\pNeed a channel and an instrument number.");
- dcmdDrawLine("\peg. Play setchan 1 10");
- return;
- }
- SetProgramChannel(channel, instrument);
- }
- else
- {
- dcmdDrawLine ("\pNot implemented.");
- }
- break;
- }
- } // CommandEntry
-
- #endif
-
-
-
- /***
- * LoadIcon
- *
- * Load the icon from the fake code or the resource
- ***/
- void LoadIcon( )
- {
- #if defined(SONICDCMD) || defined(SONICINIT)
- gGlobals.iconHdl = NewHandleSys(kIconSize);
- if (gGlobals.iconHdl)
- {
- BlockMove((Ptr)MidiIcon, *gGlobals.iconHdl, kIconSize);
- gGlobals.gotIcon = true;
- }
- #else
- gGlobals.iconHdl = (Handle)GetResource('ICN#', kIconID);
- if (gGlobals.iconHdl)
- {
- gGlobals.gotIcon = true;
- }
- else
- {
- DebugStr("\pCouldn't load icon");
- }
- #endif
- }
-
-
- /***
- * PreInitMidi
- *
- * Just initialize variables
- ***/
- void PreInitMidi()
- {
- gGlobals.soundEnabled = false;
- gGlobals.manualPatch = false;
- gGlobals.outputRefNum = 0;
- gGlobals.gotIcon = false;
- gGlobals.iconHdl = NULL;
- LoadIcon();
- }
-
-
- /***
- * InitMidi
- *
- * Sign into the midi manager
- ***/
- void InitMidi( )
- {
- OSErr err;
-
- #ifdef SONICAPP
- PreInitMidi();
- #endif
-
- if (!gGlobals.soundEnabled)
- {
-
- err = MIDIManagerSignup( );
- gGlobals.soundEnabled = (err == noErr);
- #ifdef SONICDCMD
- if (!gGlobals.soundEnabled)
- dcmdDrawLine ("\pCouldn't sign on to midi manager");
- }
- else
- dcmdDrawLine("\pAlready signed on to midi");
- #elif defined(SONICINIT)
- if (!gGlobals.soundEnabled)
- DebugStr ("\pCouldn't sign on to midi manager");
- }
- #else
- }
- #endif
-
- }
-
-
- /***
- * KillMidi
- *
- * Sign out from midi
- ***/
- void KillMidi( )
- {
- OSErr err;
- err = SilenceAll();
- MIDISignOut(gGlobals.clientID);
-
- #ifdef SONICDCMD
- dcmdDrawLine ("\pSigned out from midi manager");
- #endif
-
- gGlobals.soundEnabled = false;
- }
-
-
- /***
- * MIDIManagerSignup
- *
- * Sign into the midi manager (put the icon in the patch pay)
- ***/
- OSErr MIDIManagerSignup( )
- {
- MIDIPortParams init;
- OSErr err;
- long MIDIMgrVerNum;
- OSType sdbClientID;
-
- /* see if the midi manager is installed and remember version number */
- MIDIMgrVerNum = SndDispVersion( midiToolNum);
- if (MIDIMgrVerNum == 0)
- return errNoMIDIManager;
-
- /* sign into the manager */
- /* by finding an unused name */
- for (err = midiDupIDErr, sdbClientID = kStartSignature;
- err == midiDupIDErr && (sdbClientID - kStartSignature) < kMaxClients;
- sdbClientID++)
- {
- if ((err = MIDISignIn(sdbClientID, refCon0, gGlobals.iconHdl, "\pSonic Debug")) == noErr)
- break;
- }
- if (err != noErr)
- {
- #ifdef SONICINIT
- DebugStr("\perror signing in");
- #endif
- return err;
- }
-
- gGlobals.clientID = sdbClientID;
-
- // Assume not a Patchbay configuration.
- gGlobals.manualPatch = true;
-
- // Add an output port.
- init.portID = outputPortID;
- init.portType = midiPortTypeOutput;
- init.timeBase = 0;
- init.offsetTime = midiGetCurrent;
- init.readHook = NULL;
- init.refCon = (long) &gGlobals;
- Pstrcpy(init.name, "\pOutput");
- err = MIDIAddPort(sdbClientID, outputPortBuffSize, &gGlobals.outputRefNum, &init);
-
- // Has a PatchBay connection been resolved?
- if (err == midiVConnectMade)
- {
- gGlobals.manualPatch = false;
- }
- else if (err != noErr)
- {
- // MIDISignOut(sdbClientID);
- #ifdef SONICINIT
- DebugStr("\pError adding the port");
- #endif
- return err;
- }
-
- return noErr;
- }
-
-
- /***
- * MIDIManagerConnect
- *
- * Connect this midi device to the player.
- ***/
- OSErr MIDIManagerConnect( )
- {
- OSErr err;
-
- if (gGlobals.manualPatch)
- {
- // ••• this doesnt work. I dont know the input port for 'amdr' Apple Midi Driver
- err = MIDIConnectData( gGlobals.clientID, outputPortID, 'amdr', inputPortID);
- if (err != noErr)
- {
- #ifdef SONICDCMD
- dcmdDrawLine("\pCouldn't connect to Midi Manager");
- #endif
- return err;
- }
- }
- return noErr;
- }
-
-
-
- /***
- * StartNote
- *
- * Start playing a note to the given:
- * channel (1-16)
- * pitch (1-127)
- * velocity (loudness) (1-127)
- ***/
- OSErr StartNote(char channel, char pitch, char velocity)
- {
- OSErr err = noErr;
-
- if (gGlobals.soundEnabled)
- {
- MIDIPacket output;
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
-
- output.data[0] = 0x90 + channel - 1; // 0x90 is Note On code
- output.data[1] = pitch;
- output.data[2] = velocity;
-
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
-
- }
- return err;
- }
-
-
- /***
- * StopNote
- *
- * Start playing the note given:
- * channel (1-16)
- * pitch (0-127)
- *
- * if pitch is zero, it stops all notes on the channel
- ***/
- OSErr StopNote(char channel, char pitch)
- {
- OSErr err = noErr;
- if (gGlobals.soundEnabled)
- {
- MIDIPacket output;
-
- if (pitch > 0)
- {
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
-
- output.data[0] = 0x80 + channel - 1; // 0x80 is Note On code
- output.data[1] = pitch;
- output.data[2] = 0;
-
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
- }
- else
- {
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
- output.data[0] = 0xB0 + channel - 1;
- output.data[1] = 120; // all sound off code
- output.data[2] = 0;
-
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
-
- if (err == noErr)
- {
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
- output.data[0] = 0xB0 + channel - 1;
- output.data[1] = 123; // all notes off code
- output.data[2] = 0;
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
- }
- }
- }
- return err;
- }
-
-
- /***
- * SetPanPot
- *
- * Set the position (R/L) for the given channel (0-127)
- ***/
- OSErr SetPanPot(char channel, char position)
- {
- OSErr err = noErr;
- if (gGlobals.soundEnabled)
- {
- MIDIPacket output;
-
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
-
- output.data[0] = 0xB0 + channel - 1;
- output.data[1] = 10; // pan pot code
- output.data[2] = position;
-
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
- }
- return err;
- }
-
-
- /***
- * SetProgramChannel
- *
- * Set the voice (instrument) for a given channel.
- ***/
- OSErr SetProgramChannel(char channel, char voice)
- {
- OSErr err = noErr;
- if (gGlobals.soundEnabled)
- {
- MIDIPacket output;
-
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
-
- output.data[0] = 0xB0 + channel - 1;
- output.data[1] = 32; // Bank Select LSB
- output.data[2] = voice;
-
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
-
- if (err == noErr)
- {
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
-
- output.data[0] = 0xC0 + channel - 1;
- output.data[1] = 0; // The value of this doesn't seem to matter
- output.data[2] = voice - 1;
-
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
- }
- }
- return err;
- }
-
-
- /***
- * SilenceAll
- *
- * Make all sounds stop on all channels
- ***/
- OSErr SilenceAll()
- {
- OSErr err = noErr;
- if (gGlobals.soundEnabled)
- {
- short channel;
- MIDIPacket output;
- // try and shut up each of 16 MIDI channels
-
- for (channel = 1; channel <= 16; channel++)
- {
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
- output.data[0] = 0xB0 + channel - 1;
- output.data[1] = 120; // all sound off code
- output.data[2] = 0;
-
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
-
- if (err == noErr)
- {
- output.flags = midiMsgType + midiTimeStampCurrent + midiNoCont;
- output.len = 9;
- output.tStamp = 0;
- output.data[0] = 0xB0 + channel - 1;
- output.data[1] = 123; // all notes off code
- output.data[2] = 0;
- err = MIDIWritePacket(gGlobals.outputRefNum, &output);
- }
-
- }
- }
-
- return err;
- }
-
-
-
- /***
- * Some standard Pascal string operations
- *
- * borrowed from Sven Axelsson, GU (thanks)
- ***/
-
-
- // concat s2 to s1
- char *
- Pstrcat(
- register unsigned char *s1,
- register unsigned char *s2 )
- {
- register unsigned int i;
- unsigned int l = s2[0];
- char *s = (char *) s1;
-
- s1 = &s1[s1[0]];
- for( i = 1; i <= l; i++ ) {
- *++s1 = *++s2;
- }
- s[0] += --i;
-
- return( s );
- }
-
-
- // copy s2 into s1
- char *
- Pstrcpy(
- register unsigned char *s1,
- register unsigned char *s2 )
- {
- register unsigned int i;
- unsigned int l = s2[0];
- char *s = (char *) s1;
-
- for( i = 0; i <= l; i++ ) {
- *s1++ = *s2++;
- }
-
- return( s );
- }
-
-
- // compare s1 and s2 (zero if equal)
- short
- Pstrcmp(
- register Str255 s1,
- register Str255 s2 )
- {
- register unsigned int i;
- register short cmp;
- unsigned int l = s1[0];
-
- for( i = 0; i <= l; i++ ) {
- cmp = *s1++ - *s2++;
- if( cmp ) {
- return( cmp );
- }
- }
-
- return( 0 );
- }
-
-